Micron Document
🎖️GitЯра🎖️


Displaying Raw • Download

core/takserver/src/commonMain/kotlin/org/meshtastic/core/takserver/CotDeliveryDedup.kt 65a1f5ce4d0e4b8eafcd0bbfccafd41dc6ee888a (65a1f5ce) Text, 3.29 KB

T8b949e/*
* Copyright (c) 2026 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
Tff7b72package T7ee787org.meshtastic.core.takserver

Tff7b72import T7ee787kotlin.time.Clock
Tff7b72import T7ee787kotlin.time.Duration
Tff7b72import T7ee787kotlin.time.Duration.Companion.minutes
Tff7b72import T7ee787kotlin.time.Instant

T8b949e/**
* Suppresses duplicate CoT events before they are injected into the local TAK client.
*
* The mesh can hand the bridge the same logical CoT more than once — a packet relayed over several LoRa paths, or a
* sender that retransmits — which makes ATAK show duplicate chat / TAK-Talk messages. This is a small TTL cache keyed
* by the exact, already-normalized CoT XML: an identical event seen within [ttl] is dropped, while genuine updates (a
* PLI with a new position, a moved marker, …) differ in content and pass through untouched.
*
* Scope: this only dedupes what the *bridge* injects. It cannot see copies the TAK client also receives over another
* transport (e.g. Wi-Fi network SA); for those the client dedupes by `uid`, which is why the SDK preserves the original
* uid/timestamps across the mesh round-trip so the two copies collapse client-side.
*
* Not thread-safe by design: it is confined to the single mesh-packet collector coroutine (`meshPacketFlow.collect {
* handleMeshPacket(it) }`), which processes packets sequentially.
*/
Tff7b72internal Tff7b72class T56d364CotDeliveryDedupTb4b4b4(
Tff7b72private Tff7b72val Te6edf3ttlTb4b4b4: Te6edf3Duration Tff7b72= Te6edf3DEFAULT_TTLTb4b4b4,
Tff7b72private Tff7b72val Te6edf3maxEntriesTb4b4b4: Tffa657Int Tff7b72= Te6edf3DEFAULT_MAX_ENTRIESTb4b4b4,
Tff7b72private Tff7b72val Te6edf3nowTb4b4b4: Tb4b4b4(Tb4b4b4) Tff7b72-Tff7b72> Te6edf3Instant Tff7b72= Te6edf3ClockTb4b4b4.Te6edf3SystemTff7b72::Te6edf3nowTb4b4b4,
Tb4b4b4) Tb4b4b4{
T8b949e// normalized XML -> last-seen time. Insertion-ordered: entries are re-inserted on each
T8b949e// sighting so the iteration order is oldest-first, which makes [evictExpired] cheap.
Tff7b72private Tff7b72val Te6edf3seen Tff7b72= Te6edf3LinkedHashMapTff7b72<Tffa657StringTb4b4b4, Te6edf3InstantTff7b72>Tb4b4b4(Tb4b4b4)

T8b949e/**
* @return true if [normalizedXml] should be delivered (it is new, or its previous copy has aged past [ttl]); false
* if it is a duplicate already delivered within [ttl] (drop it).
*/
Tff7b72fun Td2a8ffadmitTb4b4b4(Te6edf3normalizedXmlTb4b4b4: Tffa657StringTb4b4b4)Tb4b4b4: Tffa657Boolean Tb4b4b4{
Tff7b72val Te6edf3t Tff7b72= Te6edf3nowTb4b4b4(Tb4b4b4)
Te6edf3evictExpiredTb4b4b4(Te6edf3tTb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3seenTb4b4b4.Te6edf3containsKeyTb4b4b4(Te6edf3normalizedXmlTb4b4b4)Tb4b4b4) Tff7b72return Tff7b72false T8b949e// survived eviction => still within ttl
Te6edf3seenTff7b72[Te6edf3normalizedXmlTff7b72] Tff7b72= Te6edf3t
Tff7b72while Tb4b4b4(Te6edf3seenTb4b4b4.Te6edf3size Tff7b72> Te6edf3maxEntriesTb4b4b4) Te6edf3seenTb4b4b4.Te6edf3removeTb4b4b4(Te6edf3seenTb4b4b4.Te6edf3keysTb4b4b4.Te6edf3firstTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72return Tff7b72true
Tb4b4b4}

Tff7b72private Tff7b72fun Td2a8ffevictExpiredTb4b4b4(Te6edf3tTb4b4b4: Te6edf3InstantTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3it Tff7b72= Te6edf3seenTb4b4b4.Te6edf3entriesTb4b4b4.Te6edf3iteratorTb4b4b4(Tb4b4b4)
Tff7b72while Tb4b4b4(Tffa657itTb4b4b4.Te6edf3hasNextTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4{
T8b949e// Oldest-first: stop at the first entry still within the window.
Tff7b72if Tb4b4b4(Te6edf3t Tff7b72- Tffa657itTb4b4b4.Te6edf3nextTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3value Tff7b72> Te6edf3ttlTb4b4b4) Tffa657itTb4b4b4.Te6edf3removeTb4b4b4(Tb4b4b4) Tff7b72else Tff7b72break
Tb4b4b4}
Tb4b4b4}

Tff7b72companion Tff7b72object Tb4b4b4{
Tff7b72val Te6edf3DEFAULT_TTLTb4b4b4: Te6edf3Duration Tff7b72= T79c0ff2.Te6edf3minutes
Tff7b72const Tff7b72val Te6edf3DEFAULT_MAX_ENTRIESTb4b4b4: Tffa657Int Tff7b72= T79c0ff5T79c0ff1T79c0ff2
Tb4b4b4}
Tb4b4b4}

Served by rngit 1.5.0 - Generated in 0.12s